<?php

/**
 * Manages the transmission of push notifications from the server to the push notification servers (both iOS and android), as well as managing the list of registered devices
 * Normally invoked through the command line, but can be invoked via the web interface as well.
 * @author Andrew Pigram
 * @version 1.0
 * @package default
 */

/**
 * Connect to the MySQL database, specifically the users table
 * @return \mysqli The database object
 */
function connectToDatabase() {
    // connect to the MySQL database, and pull a list of device tokens from it
    return new mysqli("rmplanner.net", "rmplanne_andrew", "Pi39RQ", "rmplanne_rmplanner");
}

/**
 * Connect the socket to the Apple Push Notification Server
 * @return resource The SSL socket
 */
function connectToAPNS() {
    $apnsHost = "gateway.sandbox.push.apple.com";
    $apnsPort = 2195;
    $apnsCert = "aps-development.pem";
    $streamContext = stream_context_create();
    stream_context_set_option($streamContext, 'ssl', 'local_cert', $apnsCert);
    $socket = stream_socket_client('ssl://' . $apnsHost . ':' . $apnsPort, $error, $errorString, 2, STREAM_CLIENT_CONNECT, $streamContext);
    if (isset($errorString))
        echo "$errorString\n";
    return $socket;
}

/**
 * Connect the socket to the Apple Feedback Server
 * @return resource The SSL socket
 */
function connectToAFS() {
    $feedbackPort = 2196;
    $feedbackHost = "feedback.sandbox.push.apple.com";
    $apnsCert = "aps-development.pem";
    $streamContext = stream_context_create();
    stream_context_set_option($streamContext, 'ssl', 'local_cert', $apnsCert);
    $socket = stream_socket_client('ssl://' . $feedbackHost . ':' . $feedbackPort, $error, $errorString, 2, STREAM_CLIENT_CONNECT, $streamContext);
    if (isset($errorString))
        echo "$errorString\n";
    return $socket;
}

/**
 * Construct a payload string using the required transmission protocols (APNS or Android)
 * @param string $msg The notification content string
 * @return array An array of arrays of strings and integers, used for constructing a JSON string
 */
function makePayload($msg) {
    // create the payload
    $aps = array();
    $userInfo = array();
    $aps["alert"] = $msg;
    $aps["badge"] = 1;
    $aps["sound"] = "default";
    $userInfo["content"] = $msg;
    $payload = array();
    $payload["aps"] = $aps;
    $payload["userInfo"] = $userInfo;
    return $payload;
}

/**
 * Remove deregistered devices from the device database
 * @param mysqli $db The user database
 * @todo Implement the actual removal of a device token from the database
 */
function removeDevices($db) {
    
    // remove any devices that have unregistered for push notifications
    $socket = connectToAFS();
    $tokens = array();
    $response = fread($socket, 38);
    while (!feof($socket))
    {
        // unpack the device token into a string array with key-value coding
        $tokens[] = unpack("N1timestamp/n1length/H*devToken", $response);
        
        // we only need the device token element for removal. The rest can be ignored.
        // remove the device from the database
        $db->query("DELETE FROM user_devices WHERE user_device_token='" . $tokens["devToken"] . "'");
        $db->commit();
        
        // read in the next item from the feedback server
        $response = fread($socket, 38);
    }
    
    // close the socket and the database connection
    fclose($socket);
}

/**
 * Send the notification to the APNS to push to the device referred to by the token
 * @global socket The socket pointing to the APNS
 * @param string $devToken The device token of the device the notification is to be sent to
 * @param array $payload The notification to send to the push notification server
 */
function sendToDevice($devToken, $payload, $socket) {
    // send the json encoded message to the specified device
    $json = json_encode($payload);
    $msg = chr(0) . chr(0) . chr(32) . pack("H*", $devToken) . chr(0) . chr(strlen($json)) . $json; // change size of payload to suit payload length
    fwrite($socket, $msg);
}

// connect to the MySQL database and store the fetched data in the device array
$db = connectToDatabase();

// remove any deregistered devices
removeDevices($db);

$msg = $_POST["msg"];
$user = $_POST["user"];

$result = $db->query("SELECT user_id FROM users WHERE user_login='$user'");
$db->commit();

$row = $result->fetch_assoc();
$user = $row['user_id'];

$result = $db->query("SELECT user_device_token FROM user_devices WHERE user_id=$user AND user_device_type='iOS'");
$db->commit();

$row = $result->fetch_assoc();
$devToken = $row['user_device_token'];

// compose the payload
$payload = makePayload($msg);

// connect to the APNS server if any devices are registered
$socket = connectToAPNS();

sendToDevice($devToken, $payload, $socket);

// close the socket and database
fclose($socket);
$db->close();

// print a success message
echo "Notifications sent\n";
?>
